
package com.feib.soeasy.security.captcha;

import java.io.IOException;
import java.util.Date;
import java.util.LinkedHashMap;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.util.RequestMatcher;
import org.springframework.web.filter.GenericFilterBean;

import com.feib.soeasy.model.User;
import com.feib.soeasy.model.UserActionLog;
import com.feib.soeasy.security.SoeasyDelegatingAuthenticationEntryPoint;
import com.feib.soeasy.service.UserActionLogService;
import com.feib.soeasy.service.UserService;


/**
 * @title (#)SoeasySecurityCaptchaFilter.java<br>
 * @description <br>
 * @author Jimmy Liu<br>
 * @version 1.0.0 2010/11/25
 * @copyright Far Eastern International Bank Copyright (c) 2010<br>
 * @2010/12/20 create by Jimmy Liu<br>
 */
public class SoeasySecurityCaptchaFilter extends GenericFilterBean {
    
    protected Logger logger = LoggerFactory.getLogger(this.getClass());
    

    @Autowired
    private UserService userService;

    @Autowired
    private UserActionLogService userActionLogService;

    private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
    private String filterProcessesUrl = "/soeasy_security_login";
    
    /**
     * eBIlling功能提升_第二階段, eBilling分由不同頁面登入, 改用 SoeasyDelegatingAuthenticationEntryPoint
     * @deprecated
     */
    private String failureUurl = "/login.jsp?error=10";
    
    /* eBIlling功能提升_第二階段, eBilling分由不同頁面登入 */
    @Resource(name="soeasyAuthenticationEntryPoint")
    private SoeasyDelegatingAuthenticationEntryPoint soeasyAuthenticationEntryPoint;

    /* (non-Javadoc)
     * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
     */
    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
        
        if (!requiresAuthentication(request, response)) {
            chain.doFilter(request, response);
            return;
        }

        if (logger.isDebugEnabled()) {
            logger.debug("Request is to process JCaptcha Validation");
        }
        

        //remenber that we need an id to validate!  
        String captchaId = request.getSession().getId(); 

        //retrieve the response  
        String responsestr = request.getParameter("j_captcha_response");

        // Call the Service method  
        try {  
            Boolean isResponseCorrect = CaptchaServiceSingleton.getInstance().validateResponseForID(captchaId, responsestr);

            if(null != isResponseCorrect && isResponseCorrect.booleanValue())
            {
                // 到下一個 帳號密碼驗證
                chain.doFilter(request, response);

            }
            else
            {
                logger.debug("驗證碼({})錯誤！", captchaId);

                String name = request.getParameter("j_username");
                String[] userNameTemp = name.split("_conjunction_");
                String groupNo = userNameTemp[0];// 帳單業者統一編號
                String userId = userNameTemp[1];// 使用者名稱
                logger.debug("groupNo : " + groupNo);
                logger.debug("userId : " + userId);
                
                User user = userService.loginByUerIdGroupNo(userId, groupNo);
                if (null != user)
                {
                    Integer errorTime = (null == user.getCaptchaErrorTime() ? 1 : user.getCaptchaErrorTime() + 1);
                    String logNote = "驗證碼累計錯誤 " + errorTime + "次";
                    user.setCaptchaErrorTime(errorTime);
                    if (errorTime >= 3)
                    {
                        user.setLocked(Boolean.TRUE);
                        logNote = "驗證碼累計錯誤 " + errorTime + "次，鎖定帳號";
                    }
                    userService.saveUser(user);
                    
                    // 使用者操作紀錄
                    UserActionLog log = new UserActionLog();
                    log.setInDateTime(new Date());
                    log.setGroupNo(user.getGroup().getGroupNo());
                    log.setGroupPk(user.getGroup().getGroupPk());
                    log.setUserPk(user.getUserPk());
                    log.setUserId(user.getUserId());
                    log.setUsernName(user.getUserName());
                    log.setActionBean("LoginActionBean");
                    log.setEventName("login");
                    log.setRemoteAddr(request.getRemoteAddr());         
                    log.setOutDateTime(new Date());
                    log.setLogNote(logNote);
                    userActionLogService.addUserActionLog(log);
                }
                
                SecurityContextHolder.clearContext();
                
                /* eBIlling功能提升_第二階段, eBilling分由不同頁面登入 */
                //redirectStrategy.sendRedirect(request, response, failureUurl+ "&loginType="+ request.getParameter("loginType"));
                //soeasyAuthenticationEntryPoint.commence(request, response, null);
                String failUrl = null;
                if (null != groupNo)
                {
                	if ("000000000001".equals(groupNo))
                		failUrl = "/admlogin.jsp";
                	else
                		failUrl = "/login.jsp";
                }
                else
                {
                	LinkedHashMap<RequestMatcher, AuthenticationEntryPoint> entryPoints = soeasyAuthenticationEntryPoint.getEntryPoints();
                    
                    failUrl = ((LoginUrlAuthenticationEntryPoint)soeasyAuthenticationEntryPoint.getDefaultEntryPoint()).getLoginFormUrl();
                    for (RequestMatcher requestMatcher : entryPoints.keySet()) {
            			if (requestMatcher.matches(request))
            			{
            				LoginUrlAuthenticationEntryPoint ep = (LoginUrlAuthenticationEntryPoint)entryPoints.get(requestMatcher);
            				failUrl = ep.getLoginFormUrl();
            			}
            		}
                }
                
                redirectStrategy.sendRedirect(request, response, failUrl+ "?error=10");
            }
            
        } catch (Exception e) {
            logger.warn("驗證碼發生錯誤, 不檢核驗證碼", e);
            chain.doFilter(request, response);
        } 
        
        
        
    }
    
    protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) {
        String uri = request.getRequestURI();
        int pathParamIndex = uri.indexOf(';');

        if (pathParamIndex > 0) {
            // strip everything after the first semi-colon
            uri = uri.substring(0, pathParamIndex);
        }

        if ("".equals(request.getContextPath())) {
            return uri.endsWith(filterProcessesUrl);
        }

        return uri.endsWith(request.getContextPath() + filterProcessesUrl);
    }

    
    /**
     * @param redirectStrategy the redirectStrategy to set
     */
    public void setRedirectStrategy(RedirectStrategy redirectStrategy) {
        this.redirectStrategy = redirectStrategy;
    }

    
    /**
     * @param filterProcessesUrl the filterProcessesUrl to set
     */
    public void setFilterProcessesUrl(String filterProcessesUrl) {
        this.filterProcessesUrl = filterProcessesUrl;
    }

    
}
